package dbx

import (
	"gitee.com/zhongguo168a/gocodes/datax"
	"gitee.com/zhongguo168a/gocodes/datax/mapx"
	"gitee.com/zhongguo168a/gocodes/myx/errorx"
)

func getConfig(configs []*Config) *Config {
	if len(configs) > 0 {
		return configs[0]
	}
	return nil
}

// 如果对象已经创建，将抛出异常"delay item existed"，请避免重复创建对象
// 成功提交后，需要自己处理外部的创建逻辑
func (delayQueue *DelayQueue) Create(model IDBModelDelay, data map[string]interface{}, configs ...*Config) {
	if delayQueue.isExpired {
		panic("delay is expired")
	}
	delayItem := delayQueue.getOrNewItem(model)
	// 同一个queue不能多次创建同一个对象，返回错误提示
	if delayItem != nil && (delayItem.Opt == Opt_创建 || delayItem.Opt == Opt_修改) {
		panic(errorx.New("delay item existed", datax.M{"ident": model.DBIdent()}))
	}

	conf := getConfig(configs)
	if conf == nil || !conf.EnableNil {
		data = mapx.FilterMapNotNil(data)
	}
	delayItem.Opt = Opt_创建
	delayItem.Data = data

}

// 不存在才能创建
// 注意这里不会检查字段中，是否存在对象, 使用的时候要注意
// 在数据库文档的集合中创建
// 在数据库文档的集合中创建，并保存到[dbset]字典对象中
func (delayQueue *DelayQueue) DictCreateToDBDict(dbDict IDBDict, dictItem IDBDictItem, data map[string]interface{}, configs ...*Config) {
	if delayQueue.isExpired {
		panic("delay is expired")
	}

	key := dictItem.DBIdent()
	_, hasObject := dbDict.DBGet(key)
	if hasObject { // 对象已存在
		panic(errorx.New("对象已存在"))
	}

	path := dictItem.DBPath()
	if string(path[0]) != "/" {
		panic("路径的首字符必须为/")
	}
	ident := dictItem.DBIdent()
	model := dictItem.DBModel()

	if data == nil {
		data = dictItem.DBObject().ToMap()
	}
	delayItem := delayQueue.getOrNewItem(model)
	switch delayItem.Opt {
	case Opt_删除:
		panic("文档已经被删除")
	case Opt_修改:
	case Opt_创建:
	default:
		delayItem.Opt = Opt_修改
	}

	conf := getConfig(configs)
	if conf == nil || !conf.EnableNil {
		data = mapx.FilterMapNotNil(data)
	}

	delayItem.addOptItem(&OptItem{
		Opt:   DictOpt_创建,
		Path:  path + "/" + key,
		Field: key,
		Data:  data,
	})

	// 先修改后回滚

	itemObject := dictItem.DBObject()

	dictIsNil := itemObject.RefIsNil()
	if dictIsNil {
		itemObject.RefNew()
	}

	dictObject := dbDict.DBDict()
	if dictObject.RefIsNil() {
		dictObject.RefNew()
	}
	dbDict.DBDict().RefSetObject(key, itemObject)
	itemObject.RefUpdate(data)
	delayQueue.RollbackAfter(func(ctx *AfterHandler) {
		if dictIsNil {
			itemObject.RefSetNil()
		} else {
			_ = itemObject.RefSet(ident, nil)
		}
	})

	dbDict.DBSet(key, dictItem)
	delayQueue.RollbackAfter(func(ctx *AfterHandler) {
		dbDict.DBDelete(key)
		dbDict.DBDict().RefRemove(key)
	})
}

//
//// 删除数据模型内部的集合的键
//func (delayQueue *DelayQueue) DictCreateByModelPath(origin IDBModelDelay, dictPath, dictIdent string, data interface{}, configs ...*Config) {
//	delayQueue.dictCreateByPath(origin, origin.RefGetObject(dictPath), dictPath, data, configs...)
//}
//
//// 删除数据模型内部的集合的键
//func (delayQueue *DelayQueue) DictCreateByDictPath(origin IDBDictItem, path string, data interface{}, configs ...*Config) {
//	delayQueue.dictCreateByPath(origin.DBModel(), origin.DBModel(), origin.DBPath()+"/"+origin.DBIdent()+path, data, configs...)
//}
//
//// model 文档模型对象
//// dictObject 字典对象
//func (delayQueue *DelayQueue) dictCreateByPath(model IDBModelDelay, dictObject cachex.IObject, path string, data interface{}, configs ...*Config) {
//	if delayQueue.isExpired {
//		panic("delay is expired")
//	}
//	if path == "" {
//		panic("dictPath is null")
//	}
//	if string(path[0]) != "/" {
//		panic("路径的首字符必须为/")
//	}
//	if dictObject.RefIsNil() {
//		panic("dictObject is nil")
//	}
//
//	delayItem := delayQueue.getOrNewItem(model)
//	switch delayItem.Opt {
//	case Opt_删除:
//	case Opt_修改:
//	case Opt_创建:
//	default:
//		delayItem.Opt = Opt_修改
//	}
//	conf := getConfig(configs)
//	if conf == nil || !conf.EnableNil {
//		switch d := data.(type) {
//		case map[string]interface{}:
//			if d == nil {
//				panic("不能为nil")
//			}
//			data = mapx.FilterMapNotNil(d)
//		case nil:
//			panic("不能为nil")
//		}
//	}
//
//	delayItem.addOptItem(&OptItem{
//		Opt:  Opt_修改,
//		Path: path,
//		Data: data,
//	})
//
//	// 先修改后回滚
//	dictIsNil := dictObject.RefIsNil()
//	if dictIsNil {
//		dictObject.RefNew()
//	}
//	_ = dictObject.RefSet(path, data)
//	delayQueue.RollbackAfter(func(ctx *AfterHandler) {
//		if dictIsNil {
//			dictObject.RefSetNil()
//		} else {
//			_ = dictObject.RefSet(path, nil)
//		}
//	})
//}
